#ifndef BTL_IMAGEVIEW_H
#define BTL_IMAGEVIEW_H

#include <btl/Image/Image.hpp>
#include <QWidget>
#include <QImage>
#include <QLabel>
#include <QGridLayout>

namespace btl
{
namespace extra
{
namespace gui
{

template <typename ImageRegionType>
class QImageView : public QWidget
{

   public:

      QImageView(QWidget* pParent, Qt::WindowFlags flags);

      QImageView(const ImageRegionType& im, QWidget* pParent, Qt::WindowFlags flags);

      virtual ~QImageView(void);

      QSize sizeHint(void) const;

      virtual void setImage(const ImageRegionType&);

      void unsetImage(void);

   protected:

      QLabel* _pLblImage;

      bool _isImageLoaded;

      QImage* _pImage;

};

typedef QImageView<ImageRegionConstGrey> QImageViewGrey;
typedef QImageView<ImageRegionConstRGB> QImageViewRGB;

} //namespace gui
} //namespace extra
} //namespace btl


namespace btl
{
namespace extra
{

using gui::QImageView;
using gui::QImageViewGrey;
using gui::QImageViewRGB;

} //namespace extra
} //namespace btl


// ====================================================================
// === Implementation

namespace btl
{
namespace extra
{
namespace gui
{

template <typename ImageRegionType>
QImageView<ImageRegionType>::QImageView(QWidget* pParent = 0, Qt::WindowFlags flags = 0) :
   QWidget(pParent, flags)
{
   _pImage = 0;
   _isImageLoaded = false;
   QGridLayout* pLayout = new QGridLayout(this);
   _pLblImage = new QLabel(this);
   pLayout->addWidget(_pLblImage);
   setLayout(pLayout);
   _pLblImage->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
}

template <typename ImageRegionType>
QImageView<ImageRegionType>::QImageView(const ImageRegionType& im, QWidget* pParent = 0, Qt::WindowFlags flags = 0) :
   QImageView(pParent, flags)
{
   setImage(im);
}

template <typename ImageRegionType>
inline QImageView<ImageRegionType>::~QImageView(void) {}

template <typename ImageRegionType>
QSize QImageView<ImageRegionType>::sizeHint(void) const
{
   if(_isImageLoaded)
      return QSize(_pImage->width(), _pImage->height());
   return QSize(0, 0);
}

template <typename ImageRegionType>
struct SetImageHelper
{
   static QImage* setImage(const ImageRegionType& image);
};

template <>
struct SetImageHelper<ImageRegionConstGrey>
{
   static QImage* setImage(const ImageRegionConstGrey& image)
   {
      int width = image.width();
      int height = image.height();
      QImage* pQimage = new QImage(width, height, QImage::Format_Indexed8);
      for(int i = 0; i < 256; ++i) pQimage->setColor(i, qRgb(i, i, i));
      for(int y = 0; y < height; ++y)
      {
         for(int x = 0; x < width; ++x)
         {
            PixelGrey pixel = image[y][x];
            pQimage->setPixel(x, y, pixel);
         }
      }
      return pQimage;
   }
};

template <>
struct SetImageHelper<ImageRegionConstRGB>
{
   static QImage* setImage(const ImageRegionConstRGB& image)
   {
      int width = image.width();
      int height = image.height();
      QImage* pQimage = new QImage(width, height, QImage::Format_RGB32);
      for(int y = 0; y < height; ++y)
      {
         for(int x = 0; x < width; ++x)
         {
            PixelRGB pixel = image[y][x];
            pQimage->setPixel(x, y, qRgb(pixel.red(), pixel.green(), pixel.blue()));
         }
      }
      return pQimage;
   }
};

template <typename ImageRegionType>
inline void QImageView<ImageRegionType>::setImage(const ImageRegionType& image)
{
   delete _pImage;
   _pImage = SetImageHelper<ImageRegionType>::setImage(image);
   _pLblImage->setPixmap(QPixmap::fromImage(*_pImage));
   _pLblImage->resize(_pLblImage->pixmap()->size());
   _isImageLoaded = true;
   resize(sizeHint());
}

/*
template <>
void QImageView<ImageRegionConstGrey>::setImage(const ImageRegionConstGrey& image)
{
   int width = image.width();
   int height = image.height();
   delete _pImage;
   _pImage = new QImage(width, height, QImage::Format_Indexed8);
   for(int i = 0; i < 256; ++i) _pImage->setColor(i, qRgb(i, i, i));
   for(int y = 0; y < height; ++y)
   {
      for(int x = 0; x < width; ++x)
      {
         PixelGrey pixel = image(x,y);
         _pImage->setPixel(x, y, pixel);
      }
   }
   _pLblImage->setPixmap(QPixmap::fromImage(*_pImage));
   _pLblImage->resize(_pLblImage->pixmap()->size());
   _isImageLoaded = true;
   resize(sizeHint());
}

template <>
void QImageView<ImageRegionConstRGB>::setImage(const ImageRegionConstRGB& image)
{
   int width = image.width();
   int height = image.height();
   delete _pImage;
   _pImage = new QImage(width, height, QImage::Format_RGB32);
   for(int y = 0; y < height; ++y)
   {
      for(int x = 0; x < width; ++x)
      {
         PixelRGB pixel = image(x,y);
         _pImage->setPixel(x, y, qRgb(pixel.r, pixel.g, pixel.b));
      }
   }
   _pLblImage->setPixmap(QPixmap::fromImage(*_pImage));
   _pLblImage->resize(_pLblImage->pixmap()->size());
   _isImageLoaded = true;
   resize(sizeHint());
}
*/

template <typename ImageRegionType>
void QImageView<ImageRegionType>::unsetImage(void)
{
   if(_isImageLoaded)
   {
      delete _pImage;
      _pImage = 0;
      _isImageLoaded = false;
      resize(sizeHint());
   }
}

} //namespace gui
} //namespace extra
} //namespace btl


#endif //BTL_IMAGEVIEW_H
